package com.example.ly_music

import android.content.Intent
import android.os.Bundle
import android.view.KeyEvent
import androidx.media.session.MediaButtonReceiver
import android.support.v4.media.session.PlaybackStateCompat
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.MediaMetadataCompat
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.net.Uri
import android.os.Build
import androidx.core.content.FileProvider
import java.io.File
import android.provider.Settings
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.media.app.NotificationCompat as MediaNotificationCompat
import java.net.HttpURLConnection
import java.net.URL

class MainActivity : FlutterActivity() {
    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var channel: MethodChannel
    private lateinit var installerChannel: MethodChannel
    private var notificationManager: NotificationManager? = null
    private var currentTitle: String = "正在播放"
    private var currentArtist: String = ""
    private var currentArtBitmap: Bitmap? = null
    private val NOTIFICATION_CHANNEL_ID = "ly_music_playback"
    private val NOTIFICATION_ID = 1001

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        // 建立与Flutter的通信通道
        channel = MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            "com.example.ly_music/media_controls"
        )

        // 初始化MediaSession以接收方向盘/系统媒体按键
        mediaSession = MediaSessionCompat(this, "LyMusicSession").apply {
            setFlags(
                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
            )

            setCallback(object : MediaSessionCompat.Callback() {
                override fun onSkipToNext() {
                    try { channel.invokeMethod("skipToNext", null) } catch (_: Throwable) {}
                }

                override fun onSkipToPrevious() {
                    try { channel.invokeMethod("skipToPrevious", null) } catch (_: Throwable) {}
                }

                override fun onPlay() {
                    try { channel.invokeMethod("play", null) } catch (_: Throwable) {}
                }

                override fun onPause() {
                    try { channel.invokeMethod("pause", null) } catch (_: Throwable) {}
                }

                override fun onSeekTo(pos: Long) {
                    try { channel.invokeMethod("seekTo", mapOf("position" to pos)) } catch (_: Throwable) {}
                }

                override fun onMediaButtonEvent(mediaButtonIntent: Intent?): Boolean {
                    val keyEvent = mediaButtonIntent?.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
                    if (keyEvent?.action == KeyEvent.ACTION_DOWN) {
                        when (keyEvent.keyCode) {
                            KeyEvent.KEYCODE_MEDIA_NEXT -> { onSkipToNext(); return true }
                            KeyEvent.KEYCODE_MEDIA_PREVIOUS -> { onSkipToPrevious(); return true }
                            KeyEvent.KEYCODE_MEDIA_PLAY -> { onPlay(); return true }
                            KeyEvent.KEYCODE_MEDIA_PAUSE -> { onPause(); return true }
                            KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
                                try { channel.invokeMethod("togglePlayPause", null) } catch (_: Throwable) {}
                                return true
                            }
                        }
                    }
                    return super.onMediaButtonEvent(mediaButtonIntent)
                }
            })

            val state = PlaybackStateCompat.Builder()
                .setActions(
                    PlaybackStateCompat.ACTION_PLAY or
                    PlaybackStateCompat.ACTION_PAUSE or
                    PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
                    PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
                    PlaybackStateCompat.ACTION_PLAY_PAUSE or
                    PlaybackStateCompat.ACTION_SEEK_TO
                )
                .setState(PlaybackStateCompat.STATE_PAUSED, 0, 1.0f)
                .build()
            setPlaybackState(state)
            isActive = true
        }

        // 处理Flutter侧主动更新播放状态
        channel.setMethodCallHandler { call, result ->
            when (call.method) {
                "updatePlaybackState" -> {
                    val args = call.arguments as? Map<*, *>
                    val isPlaying = args?.get("isPlaying") as? Boolean ?: false
                    val position = (args?.get("position") as? Number)?.toLong() ?: 0L
                    val state = PlaybackStateCompat.Builder()
                        .setActions(
                            PlaybackStateCompat.ACTION_PLAY or
                            PlaybackStateCompat.ACTION_PAUSE or
                            PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
                            PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
                            PlaybackStateCompat.ACTION_PLAY_PAUSE or
                            PlaybackStateCompat.ACTION_SEEK_TO
                        )
                        .setState(
                            if (isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED,
                            position,
                            1.0f
                        )
                        .build()
                    mediaSession.setPlaybackState(state)
                    showPlaybackNotification(isPlaying)
                    result.success(null)
                }
                "updateNowPlaying" -> {
                    val args = call.arguments as? Map<*, *>
                    currentTitle = (args?.get("title") as? String) ?: currentTitle
                    currentArtist = (args?.get("artist") as? String) ?: ""
                    val durationMs = (args?.get("durationMs") as? Number)?.toLong() ?: 0L
                    val builder = MediaMetadataCompat.Builder()
                        .putString(MediaMetadataCompat.METADATA_KEY_TITLE, currentTitle)
                        .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, currentArtist)
                        .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, durationMs)
                    val artUri = (args?.get("artUri") as? String)
                    if (artUri.isNullOrEmpty()) {
                        mediaSession.setMetadata(builder.build())
                        showPlaybackNotification(mediaSession.controller.playbackState?.state == PlaybackStateCompat.STATE_PLAYING)
                        result.success(null)
                    } else {
                        mediaSession.setMetadata(builder.build())
                        Thread {
                            val bmp = loadBitmapFromUrl(artUri)
                            runOnUiThread {
                                currentArtBitmap = bmp
                                val mb = MediaMetadataCompat.Builder()
                                    .putString(MediaMetadataCompat.METADATA_KEY_TITLE, currentTitle)
                                    .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, currentArtist)
                                    .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, durationMs)
                                if (bmp != null) {
                                    mb.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bmp)
                                }
                                mediaSession.setMetadata(mb.build())
                                showPlaybackNotification(mediaSession.controller.playbackState?.state == PlaybackStateCompat.STATE_PLAYING)
                            }
                        }.start()
                        result.success(null)
                    }
                }
                else -> result.notImplemented()
            }
        }

        installerChannel = MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            "app.installer"
        )
        installerChannel.setMethodCallHandler { call, result ->
            when (call.method) {
                "installApk" -> {
                    val args = call.arguments as? Map<*, *>
                    val path = args?.get("filePath") as? String
                    if (path.isNullOrEmpty()) {
                        result.error("INVALID_ARGS", "filePath missing", null)
                        return@setMethodCallHandler
                    }
                    try {
                        val file = File(path)
                        val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            FileProvider.getUriForFile(
                                this,
                                applicationContext.packageName + ".fileprovider",
                                file
                            )
                        } else {
                            Uri.fromFile(file)
                        }
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                            val canInstall = packageManager.canRequestPackageInstalls()
                            if (!canInstall) {
                                val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + applicationContext.packageName))
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                                startActivity(intent)
                                result.success(null)
                                return@setMethodCallHandler
                            }
                        }
                        val intent = Intent(Intent.ACTION_VIEW)
                        intent.setDataAndType(uri, "application/vnd.android.package-archive")
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        startActivity(intent)
                        result.success(null)
                    } catch (e: Throwable) {
                        result.error("INSTALL_ERROR", e.message, null)
                    }
                }
                else -> result.notImplemented()
            }
        }
    }

    private fun ensureNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager == null) {
                notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            }
            val channel = NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                "播放控制",
                NotificationManager.IMPORTANCE_LOW
            )
            notificationManager?.createNotificationChannel(channel)
        } else if (notificationManager == null) {
            notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        }
    }

    private fun showPlaybackNotification(isPlaying: Boolean) {
        try {
            ensureNotificationChannel()
            val token = mediaSession.sessionToken
            val prevIntent = MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
            val playIntent = MediaButtonReceiver.buildMediaButtonPendingIntent(this, if (isPlaying) PlaybackStateCompat.ACTION_PAUSE else PlaybackStateCompat.ACTION_PLAY)
            val nextIntent = MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_SKIP_TO_NEXT)

            val openIntent = Intent(this, MainActivity::class.java).apply {
                action = Intent.ACTION_MAIN
                addCategory(Intent.CATEGORY_LAUNCHER)
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
            }
            val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
            val contentIntent = PendingIntent.getActivity(this, 0, openIntent, flags)

            val builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setSmallIcon(android.R.drawable.ic_media_play)
                .setContentTitle(currentTitle)
                .setContentText(currentArtist)
                .setLargeIcon(currentArtBitmap)
                .setContentIntent(contentIntent)
                .setOngoing(isPlaying)
                .setStyle(MediaNotificationCompat.MediaStyle()
                    .setMediaSession(token)
                    .setShowActionsInCompactView(0,1,2)
                )
                .addAction(NotificationCompat.Action(android.R.drawable.ic_media_previous, "上一首", prevIntent))
                .addAction(NotificationCompat.Action(
                    if (isPlaying) android.R.drawable.ic_media_pause else android.R.drawable.ic_media_play,
                    if (isPlaying) "暂停" else "播放",
                    playIntent
                ))
                .addAction(NotificationCompat.Action(android.R.drawable.ic_media_next, "下一首", nextIntent))

            val notification: Notification = builder.build()
            notificationManager?.notify(NOTIFICATION_ID, notification)
            mediaSession.setSessionActivity(contentIntent)
        } catch (_: Throwable) {
        }
    }

    private fun loadBitmapFromUrl(urlStr: String): Bitmap? {
        return try {
            val url = URL(urlStr)
            val conn = url.openConnection() as HttpURLConnection
            conn.connectTimeout = 5000
            conn.readTimeout = 5000
            conn.instanceFollowRedirects = true
            conn.doInput = true
            conn.connect()
            val stream = conn.inputStream
            val bmp = BitmapFactory.decodeStream(stream)
            stream.close()
            conn.disconnect()
            bmp
        } catch (_: Throwable) {
            null
        }
    }

    override fun onDestroy() {
        if (::mediaSession.isInitialized) {
            mediaSession.release()
        }
        super.onDestroy()
    }
}
